其實也是某天收到這個需求,一開始覺得怎麼可能,網頁要存我電腦的檔案!什麼情境才會用到這個功能...還真的有,當你的網頁是一個編輯工具,儲存可以存到自己的電腦,也可以把電腦的檔案開啟在編輯器編輯,編一編之後又可以回存回去~ 是不是!很親民的需求XD
今天我們要來介紹的就是可以幫助我們在瀏覽器上存取本機檔案的The File System Access API
前身其實稱作Native File System API,更早之前也稱作Writeable Files API。The File System Access可以讓web可以直接存取、修改使用者裝置裡面的檔案。
通常是會用在開發在web的編輯器時,EX:圖片編輯器,在線上調整圖檔顏色、濾鏡等等,存到裝置後,又想在對圖檔修改,再回存。文字編輯器的範例應用可以參考這個連結
目前支援度其實蠻少的只支援chrome, edge, opera
透過window.showOpenFilePicker選取檔案後取得的物件
//writable可透過write覆寫內容至檔案,寫完之後呼叫close關閉writable狀態
writable.write(contents);
writable.close();
打開file manager,讓使用者選取檔案
打開file manager,讓使用者選取位置後,儲存檔案
以下程式皆以vue.js為例
showOpenFilePicker
打開file manager讓使用者選取檔案注意,這邊是「不需透過input type="file"」,可以再任意的元素上ex.button上開啟file manager
<div class="section-save">
<p>模擬1: 開啟檔案</p>
<button @click="openFileNew">Open</button>
</div>
async openFileNew(){
let fileHandle;
[fileHandle] = await window.showOpenFilePicker();
//FileSystemFileHandle物件
const file = await fileHandle.getFile(); // file物件
console.log('file',file);
},
showOpenFilePicke
打開file manger,選取的檔案為FileSysteFileHandle
物件FileSysteFileHandle
物件透過getFile()
就可取得當中的file物件,便可使用之前file物件的處理方式showSaveFilePicker
writeFile
選定位置,另存新檔後,修改後可直接存至原檔showSaveFilePicker
打開save file的視窗<div class="section-save">
<p>模擬2: 第一次存新檔案,後續存回原檔</p>
<input type="text" v-model="textContent">
<button @click="saveNew">save to local</button>
</div>
/***
* 存檔
***/
async saveNew(){
const _self = this;
console.log('save new', this.saveNew);
let zip = new JSZip(); // 建立jszip物件 準備打包
zip.file('test.txt', this.textContent); //將文件檔案放到zip中
//第一次存檔 選擇位置存zip
if(_self.isSaveFirstTime){
let options = {
suggestedName: 'example.zip', //給予存檔預設名字
types:[{
accept: {
'application/zip': ['.zip'], //建議zip格式
},
}]
}
this.targetFileObject = await window.showSaveFilePicker(options); //儲存時
console.log('handle',this.targetFileObject); //FileSystemFileHandle
_self.isSaveFirstTime = false;
}
zip.generateAsync({type: 'blob'}).then(async (content)=>{
// 寫進檔案中
await _self.writeFile(this.targetFileObject, content)
_self.isSaveFirstTime = false;
})
},
/***寫入本地端檔案
* fileHandle: 需為FileSystemFileHandle物件
* contents: 要被寫入的內容
***/
async writeFile(fileHandle, contents) {
console.log("===== Write File Start =====");
//如果已經建立過createWritable,則直接覆寫
if (fileHandle.createWriter) {
const writer = await fileHandle.createWriter(); // createWriter
await writer.write(0, contents);
await writer.close();
return;
}
//為建立過createWritable,建立後覆寫
const writable = await fileHandle.createWritable(); // createWritable
await writable.write(contents);
await writable.close();
console.log("===== Write File End =====");
},
附上實際的程式檔案,給大家玩玩 [連結]
在專案開發時,寫到存檔至地端時曾經發生以下錯誤:
failed to execute 'showSaveFilePicker' on 'Window': Must be handling a user gesture to show a file picker.
這個錯誤是因為,有的時候要被儲存的檔案處理時間比較久,還正在處理的同時我們也呼叫的showSaveFilePicker的視窗,才會有這個錯誤。
建議順序可以調整成:先把存擋的位置處理好後,再去做檔案相關的處理。就確保不會有檔案還在處理又要乎呼叫showSaveFilePicker的狀況。
意即 showSaveFilePicker選完儲存位置 -> 檔案資料處理
嘮叨廢話time可跳過~~~
終於~~~ 檔案處理應該是最後一天分享了,
可能還有很多需要改進跟講得更清楚,不過因為還有別的主題還想寫,
就先把我自己很基礎的認知跟覺得很常見的應用,在這幾天介紹給他~~
明天工作上有重要的事等等要去努力一下,今天就到這邊囉,希望明天順利RRR